package com.mh.config;

import com.mh.exception.AuthEntryPointImpl;
import com.mh.filter.MyJWtAuthFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/** @EnableGlobalMethodSecurity: 启用Spring Security的全局方法安全支持
 *  这个注解告诉Spring Security 框架,你希望在方法级别上使用安全注解
 *  (如 @PreAuthorize、@PostAuthorize、@Secured 等)来实现细粒度的权限控制
 *  可以加该注解的条件: 1.该类必须被 Spring 管理 ; 2.Spring 能够扫描到该类-->但推荐加在SecurityConfig类上
 *  prePostEnabled = true: 启用@PreAuthorize和@PostAuthorize 注解,用于在方法调用前后进行权限检查
 */
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyJWtAuthFilter myJWtAuthFilter;

    @Autowired
    private AuthEntryPointImpl authEntryPoint;
    @Autowired
    private AccessDeniedHandler accessDeniedHandler;

    //BCryptPasswordEncoder注入到Spring容器
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    //注入AuthenticationManager对象,供外部类使用
    @Bean
    @Override
    protected AuthenticationManager authenticationManager() throws Exception {
        //当前类的父类WebSecurityConfigurerAdapter的
        //authenticationManager()方法返回AuthenticationManager对象
        return super.authenticationManager();
    }

    //过滤器链设置
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //关闭 CSRF(跨站请求伪造)防护-->无状态的关闭,有状态的开启
        http.csrf().disable();
        //允许跨域-->跟上面结合在一起使用
        //http.cors();

        http    // 设置会话管理策略为无状态
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                //配置路径的访问权限
                .and().authorizeRequests()
                //允许公开访问的路径,允许匿名访问：/user/login, anonymous匿名
                .antMatchers("/user/login","/captchaImage").anonymous()

                //配置的形式权限校验
                .antMatchers("/myExTest").hasAuthority("system:menu:list")

                //其他所有请求都需要认证
                .anyRequest().authenticated();

        //将自定义过滤器添加到过滤器链中(加载"用户密码认证过滤器"前面)
        http.addFilterBefore(myJWtAuthFilter, UsernamePasswordAuthenticationFilter.class);

        //配置异常处理器
        http.exceptionHandling()
                .authenticationEntryPoint(authEntryPoint) //配置认证异常 401
                .accessDeniedHandler(accessDeniedHandler); //配置授权异常 403
    }
}
